import datetime

import pandas as pd
import tushare as ts

from LSTM.variableset import EMVar, EMPath
from emmodels.em_base_data import BaseData
from emmodels.em_position import Assets
from emutils import stk_utils\
    ,draw_utils
import time
# (止损, 止盈, 是否回撤, 收益多少的时候进行回测, 回测达到多少, 买入最小偏移, 买入最大偏移, 最大持仓时间， 买入时当前价格与昨天收盘价差最少值)
ID_STOP_LOSS = 0
ID_STOP_WIN  = 1
ID_IS_REBACK = 2
ID_HIGH_PROFIT = 3
ID_MAX_REBACK = 4
ID_BUY_MIN_OFFSET = 5
ID_BUY_MAX_OFFSET = 6
ID_MAX_KEEP_DAYS = 7
ID_MIN_CUR_PRICE_TO_LAST_CLOSE = 8

# (-0.10, 0.2, True, 0.08, 0.05, -0.05, -0.015),
# (-0.10, 0.2, False,0.1,  0.10, -0.05, -0.015),
# (-0.10, 0.1, True, 0.08, 0.05, -0.05, -0.015),
# (-0.10, 0.1, True, 0.05, 0.02, -0.05, -0.015)

# (-0.10, 0.2, False, 0.1, 0.10, -0.05, -0.015, 3),
#           (-0.10, 0.2, False, 0.1, 0.10, -0.05, -0.015, 5),
#           (-0.10, 0.2, False, 0.1, 0.10, -0.05, -0.015, 10),
params = [(-0.035, 0.1, True,  0.02, 0.10, -0.10, 0, 5, -0.005),
          (-0.035, 0.1, False, 0.02, 0.10, -0.10, 0, 5, -0.005),
          (-0.035, 0.1, False, 0.02, 0.10, -0.10, 0, 5, -0.01)]

for p in params:
    # time.sleep(3600)
    stop_loss = p[ID_STOP_LOSS]
    stop_win = p[ID_STOP_WIN]
    is_reback = p[ID_IS_REBACK]
    high_profit_reback = p[ID_HIGH_PROFIT]
    max_reback = p[ID_MAX_REBACK]
    buy_min_offset = p[ID_BUY_MIN_OFFSET]
    buy_max_offset = p[ID_BUY_MAX_OFFSET]
    max_keep_days = p[ID_MAX_KEEP_DAYS]
    min_cur_price_to_last_close = p[ID_MIN_CUR_PRICE_TO_LAST_CLOSE]
    # 所有的等待买入的
    total_pend_buy_df = pd.read_csv(filepath_or_buffer=EMPath.data_file_full_path(is_common=True, fileName='total_buy.csv'), converters={EMVar.code:str})

    # 获取时间序列
    # start_date = total_pend_buy_df.head(1)[EMVar.date][0]
    start_date = '2017-01-01'

    end_date = datetime.datetime.now().strftime('%Y-%m-%d')
    # end_date = '2017-03-02'
    sh_his_datas = ts.get_k_data(code=EMVar.CODE_SH, index=True, start=start_date, end=end_date)
    date_series = sh_his_datas[EMVar.date]
    time_list = stk_utils.em_get_day_min_list()

    total_trade_days_l = stk_utils.em_get_total_trade_list()

    assets = Assets(init_assets=50000)
    assets.update_one()
    # 遍历到1天，如果可以买入，获取每天可以买入的票的分钟线 如果已经持仓，获取持仓的票的分钟线

    for date in list(date_series):
        # 买入的日期是下一天
        pend_buy_stks = total_pend_buy_df[total_pend_buy_df[EMVar.dp1_date] == date] # df
        pend_sail_stks = assets.own_stock #dic key:stkcode value:BaseModel
        date_time_list = [date+' '+x for x in time_list]

        tmp_total_min_data_pieces = []
        base_info_dic = {}

        if len(pend_sail_stks):
            for key in list(pend_sail_stks.keys()):
                if not key in base_info_dic.keys():
                    model = BaseData.select_stkcode(stkcode=key)
                    base_info_dic[key] = model.stkname
                    min_data  = stk_utils.em_resample_tick_data(code=key, date=date, need_insert_db=True)
                    if not min_data.empty:
                        tmp_total_min_data_pieces.append(min_data)

        if not pend_buy_stks.empty:
            for index, row in pend_buy_stks.iterrows():
                key = row[EMVar.code]
                # 当天的序列数据不再重复拿
                if not key in base_info_dic.keys():
                    model = BaseData.select_stkcode(stkcode=key)
                    base_info_dic[key] = model.stkname
                    min_data = stk_utils.em_resample_tick_data(code=row[EMVar.code], date=date, need_insert_db=True)
                    if not min_data.empty:
                        tmp_total_min_data_pieces.append(min_data)

        # 将所有的当天的mindata全部merge并且按照min去排列
        total_tmp_min_data = pd.DataFrame()
        if tmp_total_min_data_pieces:
            total_tmp_min_data = pd.concat(tmp_total_min_data_pieces, ignore_index=True)
            total_tmp_min_data.sort_values(EMVar.time, inplace=True)

        for date_time in date_time_list:
            # 满足上面的情况的时候 获取每天的分钟序列
            if not total_tmp_min_data.empty:
                stk_tmp_min_datas = total_tmp_min_data[total_tmp_min_data[EMVar.time] == date_time]
            # 优先卖出 然后买入
            if len(pend_sail_stks):
                for code in list(pend_sail_stks.keys()):
                    baseModel = pend_sail_stks[code]
                    bar_data = stk_tmp_min_datas[stk_tmp_min_datas[EMVar.code] == code]
                    if not bar_data.empty:
                        if assets.couldsaile(date_time=date_time, stkcode=code):
                            try:
                                bar_close_price = float(bar_data[EMVar.close])
                                if (bar_close_price - baseModel.trade_price) / baseModel.trade_price < stop_loss:
                                    print('止损卖出')
                                    assets.saile_stk(date_time=date_time, stkcode=code, name=base_info_dic[code],
                                                     price=bar_close_price,reason='止损卖出')
                                    assets.update_one()
                                    break
                                elif (bar_close_price - baseModel.trade_price) / baseModel.trade_price > stop_win:
                                    print('止盈卖出')
                                    assets.saile_stk(date_time=date_time, stkcode=code, name=base_info_dic[code],
                                                     price=bar_close_price,reason='止盈卖出')
                                    assets.update_one()
                                    break
                                if is_reback and baseModel.reback > max_reback and baseModel.high_profit>high_profit_reback:
                                    print('回撤卖出')
                                    assets.saile_stk(date_time=date_time, stkcode=code, name=base_info_dic[code],
                                                     price=bar_close_price,reason='回撤卖出')
                                    assets.update_one()
                                    break
                                if baseModel.stk_keep_days >= max_keep_days:
                                    print('持仓日大于%d卖出'%max_keep_days)
                                    assets.saile_stk(date_time=date_time, stkcode=code, name=base_info_dic[code],
                                                     price=bar_close_price, reason='持仓日大于%d卖出'%max_keep_days)
                                    assets.update_one()
                                    break
                                else:
                                    if date_time in date_time_list[::2]:
                                        assets.update_stk_assets(stkcode=code, curprice=bar_close_price, cur_date=date)
                                    if date_time == date_time_list[0]:
                                        print(baseModel)
                            except Exception as e:
                                print(e)



            if not pend_buy_stks.empty:
                for index, value in pend_buy_stks.iterrows():
                    code = value[EMVar.code]
                    # 预演当天昨日收盘
                    last_close = float(value[EMVar.close])
                    bar_data = stk_tmp_min_datas[stk_tmp_min_datas[EMVar.code] == code]
                    predict_Min = float(value[EMVar.predictMin])
                    if not bar_data.empty:
                        detect_price = float(bar_data[EMVar.close])
                        if assets.couldbuy(date_time, code, predict_Min) :
                            if not assets.is_own_stock(code):
                                cur_price_to_last_close_offset = (detect_price - last_close)/last_close
                                if cur_price_to_last_close_offset < min_cur_price_to_last_close:
                                    print('当前价格与昨天收盘 价差 %f, 无法买入'%cur_price_to_last_close_offset)
                                    continue
                                offset = (detect_price - predict_Min) / predict_Min
                                if offset<buy_max_offset and offset>buy_min_offset:
                                    # 买入价格应该是bar的close价格 而不是predictMin...汗
                                    print('当前价格偏移:%f'%offset)
                                    assets.buy_stk(date_time=date_time, stkcode=code, name=base_info_dic[code], price=detect_price, reason='offset(%f~%f)'%(buy_min_offset,buy_max_offset))
                                    assets.update_one()
                                    # draw_utils.draw_total_data(code=code, operationDate=date,
                                    #                            date_index_list=total_trade_days_l,
                                    #                            savePath=EMPath.strateg_info_file_full_path(is_common=True,strategyName=assets.strategy_name,fileName='%s_%s_buy.png'%(code,date_time)),
                                    #                            hlines=[{'y': detect_price, 'color': 'green', 'style': ':'}])














